package com.lingdong.onlinejudge.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lingdong.onlinejudge.common.ErrorCode;
import com.lingdong.onlinejudge.common.PageRequest;
import com.lingdong.onlinejudge.exception.BusinessException;
import com.lingdong.onlinejudge.mapper.*;
import com.lingdong.onlinejudge.model.dto.match.MatchCreateDto;
import com.lingdong.onlinejudge.model.dto.match.MatchQueryDto;
import com.lingdong.onlinejudge.model.dto.match.MatchUpdateDto;
import com.lingdong.onlinejudge.model.entity.*;
import com.lingdong.onlinejudge.model.vo.sign.SignVo;
import com.lingdong.onlinejudge.model.vo.match.MatchVo;
import com.lingdong.onlinejudge.model.vo.topic.TopicSimpleVo;
import com.lingdong.onlinejudge.model.vo.user.UserVo;
import com.lingdong.onlinejudge.service.AuthService;
import com.lingdong.onlinejudge.service.MatchService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author lzw
 */
@Service
public class MatchServiceImpl extends ServiceImpl<MatchMapper, Match>
        implements MatchService {


    @Resource
    private AuthService authService;

    @Resource
    private MatchMapper matchMapper;

    @Resource
    private MatchTopicMapper matchTopicMapper;

    @Resource
    private TopicMapper topicMapper;

    @Resource
    private SignMapper signMapper;

    @Resource
    private UserMapper userMapper;


    @Resource
    private SubmitMapper submitMapper;


    /**
     * 创建比赛
     *
     * @param matchCreateDto 比赛创建Dto
     * @param token          token
     * @return 结果
     */
    @Override
    public Boolean createMatch(MatchCreateDto matchCreateDto, String token) {
        Integer matchNum = matchCreateDto.getMatchNum();
        Integer matchType = matchCreateDto.getMatchType();
        Integer isExamine = matchCreateDto.getIsExamine();
        Integer matchStatus = matchCreateDto.getMatchStatus();
        String matchTitle = matchCreateDto.getMatchTitle();
        String matchHost = matchCreateDto.getMatchHost();
        String matchTip = matchCreateDto.getMatchTip();
        String intro = matchCreateDto.getIntro();
        Date startTime = matchCreateDto.getStartTime();
        Date endTime = matchCreateDto.getEndTime();
        // 参数校验
        if (matchNum == null || matchType == null ||
                isExamine == null || matchStatus == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (StringUtils.isAnyBlank(matchTitle, matchHost, matchTip, intro)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (startTime == null || endTime == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 开始时间不能大于或等于结束时间
        if (startTime.getTime() >= endTime.getTime()) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 校验人数限制
        if (matchType == 0) {
            // 个人不能超过500人
            if (matchNum > 500) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "人数超过500人");
            }
        } else {
            // 团队不能超过50个队伍
            if (matchNum > 50) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍不能超过50个");
            }
        }
        // 标题、简介、主办方、提示不能超过50字
        if (matchTitle.length() > 50 || intro.length() > 50
                || matchHost.length() > 50 || matchTip.length() > 50) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Match match = new Match();
        BeanUtils.copyProperties(matchCreateDto, match);
        UserVo userInfo = authService.getUserInfo(token);
        match.setAdminId(userInfo.getId());
        match.setCreateBy(userInfo.getId());
        boolean save = this.save(match);
        if (!save) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }
        return true;
    }

    /**
     * 更新比赛
     *
     * @param matchUpdateDto 比赛更新Dto
     * @return 结果
     */
    @Override
    public Boolean updateMatch(MatchUpdateDto matchUpdateDto) {
        Integer matchStatus = matchUpdateDto.getMatchStatus();
        String matchTitle = matchUpdateDto.getMatchTitle();
        String matchHost = matchUpdateDto.getMatchHost();
        String matchTip = matchUpdateDto.getMatchTip();
        String intro = matchUpdateDto.getIntro();
        Date startTime = matchUpdateDto.getStartTime();
        Date endTime = matchUpdateDto.getEndTime();
        // 参数校验
        if (matchStatus == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (StringUtils.isAnyBlank(matchTitle, matchHost, matchTip, intro)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (startTime == null || endTime == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 开始时间不能大于或等于结束时间
        if (startTime.getTime() >= endTime.getTime()) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 标题、简介、主办方、提示不能超过50字
        if (matchTitle.length() > 50 || intro.length() > 50
                || matchHost.length() > 50 || matchTip.length() > 50) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (matchUpdateDto.getId() == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        QueryWrapper<Match> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", matchUpdateDto.getId());
        Match match = matchMapper.selectOne(queryWrapper);
        if (match == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        BeanUtils.copyProperties(matchUpdateDto, match);
        int i = matchMapper.updateById(match);
        if (i == 0) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }
        return true;
    }

    /**
     * 查询比赛列表
     *
     * @param matchName 比赛名称
     * @return 结果
     */
    @Override
    public List<Match> getMatchList(String matchName) {
        QueryWrapper<Match> queryWrapper = new QueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(matchName), "match_title", matchName);
        return matchMapper.selectList(queryWrapper);
    }

    /**
     * 查询比赛详情
     *
     * @param id 比赛id
     * @return 结果
     */
    @Override
    public MatchVo getMatch(Long id,String token) {
        // 获取当前登录用户信息

        UserVo userInfo = authService.getUserInfo(token);
        Long userId = userInfo.getId();

        QueryWrapper<Match> matchQueryWrapper = new QueryWrapper<>();
        matchQueryWrapper.eq("id", id);
        Match match = matchMapper.selectOne(matchQueryWrapper);
        if (match == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        MatchVo matchVo = new MatchVo();
        BeanUtils.copyProperties(match, matchVo);
        // 查询比赛题目
        QueryWrapper<MatchTopic> matchTopicQueryWrapper = new QueryWrapper<>();
        matchTopicQueryWrapper.eq("match_id", id);
        List<MatchTopic> matchTopicList = matchTopicMapper.selectList(matchTopicQueryWrapper);
        List<TopicSimpleVo> topicList = new ArrayList<>();
        matchTopicList.forEach(matchTopic -> {
            QueryWrapper<Topic> topicQueryWrapper = new QueryWrapper<>();
            topicQueryWrapper.eq("id", matchTopic.getTopicId());
            Topic topic = topicMapper.selectOne(topicQueryWrapper);
            // 根据当前登录用户和题目id查询提交表,判断当前登录人是否作答
            LambdaQueryWrapper<Submit> submitQueryWrapper = new LambdaQueryWrapper<>();
            submitQueryWrapper.eq(Submit::getCreateBy,userId)
                            .eq(Submit::getTopicId,topic.getId());
            boolean isSubmit = submitMapper.selectCount(submitQueryWrapper) > 0;
            topic.setSubmitStatus(isSubmit);

            // 创建封装对象
            TopicSimpleVo topicSimpleVo = new TopicSimpleVo();
            BeanUtils.copyProperties(topic, topicSimpleVo);
            topicList.add(topicSimpleVo);
        });
        matchVo.setMatchTopicList(topicList);
        // 查询报名信息
        QueryWrapper<Sign> signQueryWrapper = new QueryWrapper<>();
        signQueryWrapper.eq("match_id", id);
        signQueryWrapper.orderByDesc("sign_exp");
        List<Sign> signList = signMapper.selectList(signQueryWrapper);
        List<SignVo> signVoList = new ArrayList<>();
        signList.forEach(sign -> {
            SignVo signVo = new SignVo();
            BeanUtils.copyProperties(sign, signVo);
            QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
            userQueryWrapper.eq("id", sign.getUserId());
            User user = userMapper.selectOne(userQueryWrapper);
            if (user == null) {
                throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
            }
            UserVo userVo = new UserVo();
            BeanUtils.copyProperties(user, userVo);
            signVo.setUser(userVo);
            signVoList.add(signVo);
        });
        matchVo.setMatchSignList(signVoList);
        return matchVo;
    }

    @Override
    public Page<Match> queryMatchByPage(MatchQueryDto matchQueryDto) {
        Integer matchType = matchQueryDto.getMatchType();
        Integer matchStatus = matchQueryDto.getMatchStatus();
        String matchTitle = matchQueryDto.getMatchTitle();
        String matchHost = matchQueryDto.getMatchHost();
        Date startTime = matchQueryDto.getStartTime();
        Date endTime = matchQueryDto.getEndTime();
        // 构造查询条件
        QueryWrapper<Match> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(matchType != null, "match_type", matchType);
        queryWrapper.eq(matchStatus != null, "match_status", matchStatus);
        queryWrapper.like(StringUtils.isNotBlank(matchTitle), "match_title", matchTitle);
        queryWrapper.like(StringUtils.isNotBlank(matchHost), "match_host", matchHost);
        queryWrapper.ge(startTime != null, "start_time", startTime);
        queryWrapper.le(endTime != null, "end_time", endTime);
        // 分页查询
        PageRequest page = matchQueryDto.getPage();
        if (page == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Page<Match> matchPage = matchMapper.selectPage(
                new Page<>(page.getCurrent(), page.getPageSize()),
                queryWrapper);
        return matchPage;
    }

    /**
     * 判断比赛是否结算分数
     *
     * @param matchId
     * @return
     */
    @Override
    public boolean isMatchFinish(Long matchId) {

        // 校验参数
        if (ObjectUtil.isNull(matchId)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        // 查找报名表 经验值求和
        LambdaQueryWrapper<Sign> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Sign::getMatchId, matchId);

        // 分数求和
        long sumSignExp = 0;

        List<Sign> signList = signMapper.selectList(queryWrapper);
        for (Sign sign : signList) {
            sumSignExp += sign.getSignExp();
        }


        // 分数总和>0 视为完成结算
        return sumSignExp > 0;
    }


    /**
     * 根据比赛id 获取试题列表
     * @param matchId 比赛id
     * @return 试题列表
     */
    @Override
    public List<Topic> getTopicByMatchId(Long matchId) {
        // 校验参数
        if (ObjectUtil.isNull(matchId)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        // 查询比赛题目
        QueryWrapper<MatchTopic> matchTopicQueryWrapper = new QueryWrapper<>();
        matchTopicQueryWrapper.eq("match_id", matchId);
        List<MatchTopic> matchTopicList = matchTopicMapper.selectList(matchTopicQueryWrapper);
        List<Topic> topicList = new ArrayList<>();
        matchTopicList.forEach(matchTopic -> {
            QueryWrapper<Topic> topicQueryWrapper = new QueryWrapper<>();
            topicQueryWrapper.eq("id", matchTopic.getTopicId());
            Topic topic = topicMapper.selectOne(topicQueryWrapper);
            topicList.add(topic);
        });

        return topicList;
    }
}




